import Snake from '@/scripts/snake'
import View from '@/scripts/view'
import { SPEED_TIME_INTERVAL, WINDOW_HEIGHT, WINDOW_WIDTH } from '@/scripts/args'
import { getRandomInt, Position } from '@/scripts/util'
import { Direction } from '@/scripts/enum'

export default function Game (ctx, config) {

  const { objects: { walls, gates, traps }, scene: { maxFoodCount, size }, snake: { speed, length, x, direction, y } } = config

  this.ctx = ctx
  this.snake = new Snake({ size, direction, length, x, y })
  this.foods = []
  this.walls = walls
  this.gates = gates
  this.traps = traps
  this.maxFoodCount = maxFoodCount
  this.speed = speed


  this.score = 0
  this.eatFoodFlag = false

  this.row = WINDOW_WIDTH / size
  this.col = WINDOW_HEIGHT / size

  this.view = new View(ctx, config)
}

Game.prototype = {
  clear () {
    // this.snake = new Snake()
    // this.foods = []
    // this.walls = []
    // this.gate = []
    // this.trap = []
    //
    // this.maxFoodCount = 15
    //
    // this.speed = 7
    //
    // this.eatFoodFlag = false
  },
  init () {
    const game = this
    document.onkeydown = function ({ code }) {
      code = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'KeyQ', 'KeyE'].includes(code) ? code : 'other'
      const option = {
        ArrowUp: () => game.changeSnakeDirection(Direction.Up),
        ArrowDown: () => game.changeSnakeDirection(Direction.Down),
        ArrowLeft: () => game.changeSnakeDirection(Direction.Left),
        ArrowRight: () => game.changeSnakeDirection(Direction.Right),
        KeyQ: () => game.speedUp(),
        KeyE: () => game.speedDown(),
        other: () => {}
      }
      option[code]()
      // preventDefault()
    }

    const points = []
    /*
      init free points
     */
    for (let i = 0; i < this.row; i++) {
      points[i] = []
      for (let j = 0; j < this.col; j++) {
        points[i][j] = true
      }
    }

    this.freePosition = points

    /*
      remove walls points
     */
    for (let pos of this.walls) {
      const { x, y } = pos
      this.freePosition[x][y] = false
    }

    /*
      remove traps points
     */
    for (let pos of this.traps) {
      const { x, y } = pos
      this.freePosition[x][y] = false
    }

    /*
      remove gates points
     */
    for (let gate of this.gates) {
      const { x, y } = gate.position
      this.freePosition[x][y] = false
    }

    /*
        remove snake from free points
    */
    for (let pos of this.snake.body) {
      const { x, y } = pos
      if (x < 0 || y < 0) continue
      this.freePosition[x][y] = false
    }

    /*
      foods
     */
    for (let i = 0; i < this.maxFoodCount; i++) {
      this.generateFood()
    }
  },
  start () {
    this.render()
  },
  refresh () {
    this.snake.move(this.eatFoodFlag)
    if (this.eatFoodFlag) this.eatFoodFlag = false
    this.collisionCheck()
    this.view.init()
    this.view.drawFoods(this.foods)
    this.view.drawGates(this.gates)
    this.view.drawWalls(this.walls)
    this.view.drawTraps(this.traps)
    this.view.drawSnake(this.snake)
  },
  render () {
    this.view.init()
    this.game_timer = setInterval(() => this.refresh(), SPEED_TIME_INTERVAL[this.speed])
  },
  changeSnakeDirection (direction) {
    this.snake.changeDirection(direction)
  },
  generateFood () {
    let flag = true
    while (flag) {
      const x = getRandomInt(0, this.row)
      const y = getRandomInt(0, this.col)
      if (this.freePosition[x][y]) {
        this.foods.push(new Position(x, y))
        this.freePosition[x][y] = false
        flag = false
      }
    }
  },
  /**
   * 碰撞检测
   */
  collisionCheck () {
    if (this.snake.direction === Direction.Stop) return
    const head = this.snake.head
    /*
      食物碰撞
     */
    for (let food of this.foods) {
      if (head.equals(food)) {
        this.score += +this.speed * this.snake.length()
        this.scoreChange(this.score)
        this.removeFood(food)
      }
    }
    /*
      蛇身碰撞
     */
    for (let item of this.snake.body) {
      if (head.equals(item)) {
        setTimeout(() => alert('game over'), 8)
        clearInterval(this.game_timer)
      }
    }
    /*
      墙碰撞
     */
    for (let wall of this.walls) {
      if (head.equals(wall)) {
        setTimeout(() => alert('game over'), 8)
        clearInterval(this.game_timer)
      }
    }
    /*
      地刺碰撞
     */
    for (let trap of this.traps) {
      if (head.equals(trap)) {
        /*
          撞到地刺，蛇长度 -1
         */
        this.snake.removeTail()
        this.score -= +this.speed * this.snake.length()
        if (this.snake.length() <= 0) {
          setTimeout(() => alert('game over'), 8)
          clearInterval(this.game_timer)
        }
      }
    }
    /*
      传送门碰撞
     */
    for (let { position, aim, direction } of this.gates) {
      if (head.equals(position)) {
        this.snake.moveHeadTo(aim)
        this.snake.changeDirection(direction, true)
      }
    }
  },
  removeFood (food) {
    this.freePosition[food.x][food.y] = true
    this.foods = this.foods.filter(item => {
      return !item.equals(food)
    })
    this.eatFoodFlag = true
    this.generateFood()
  },
  gameOver () {},
  speedUp () {
    if (this.speed < 8) this.speed += 1
    clearInterval(this.game_timer)
    this.render()
  },
  speedDown () {
    if (this.speed > 0) this.speed -= 1
    clearInterval(this.game_timer)
    this.render()
  },
  bindScoreChangeEvent(handler) {
    Game.prototype.scoreChange = handler
  },
  abort() { clearInterval(this.game_timer)}
}

export function Gate (x1, y1, x2, y2, direction) {
  this.position = new Position(x1, y1)
  this.aim = new Position(x2, y2)
  this.direction = direction
}